package com.hmall.gateway.filter;

import com.hmall.common.exception.UnauthorizedException;
import com.hmall.common.utils.CollUtils;
import com.hmall.gateway.config.AuthProperties;
import com.hmall.gateway.utils.JwtTool;
import lombok.RequiredArgsConstructor;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.util.AntPathMatcher;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import java.util.List;

/**
 * 全局登录校验过滤器：用于拦截未登录状态下的请求访问
 */
@Component
//使用RequiredArgsConstructor注解时，下面注入的必须用final修饰
@RequiredArgsConstructor
@EnableConfigurationProperties(AuthProperties.class)
public class AuthGlobalFilter implements GlobalFilter, Ordered {

    private final JwtTool jwtTool;

    private final AuthProperties authProperties;

    private final AntPathMatcher antPathMatcher = new AntPathMatcher();

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        // 1.获取Request
        ServerHttpRequest request = exchange.getRequest();
        // 2.判断是否需要做登录拦截
        if(isExclude(request.getPath().toString())){
            // 无需拦截，直接放行
            return chain.filter(exchange);
        }
        // 3.获取请求头中的token
        String token = null;
        List<String> headers = request.getHeaders().get("authorization");
        if (headers != null && !headers.isEmpty()) {
            token = headers.get(0);
        }
        // 4.校验并解析token
        Long userId = null;
        try {
            //调用JWT工具类的parseToken方法，从传入的token中解析出用户ID（userId）
            userId = jwtTool.parseToken(token);
        } catch (UnauthorizedException e) {
            // 获取当前HTTP请求对应的响应对象（用于构建并返回错误响应）
            ServerHttpResponse response = exchange.getResponse();
            // 设置响应的原始状态码为401（HTTP 401 Unauthorized，标准未授权状态码）
            response.setStatusCode(HttpStatus.UNAUTHORIZED);
            // 返回"响应完成"的结果，中断请求后续处理流程，直接将401响应返回给客户端
            return response.setComplete();
        }
        // 5.传递用户信息
        String userInfo = userId.toString();
        // (1)构建修改后的ServerWebExchange实例
        // ServerWebExchange是Spring WebFlux中封装HTTP请求-响应上下文的核心对象，包含请求、响应、属性等信息
        // 由于ServerWebExchange通常是不可变的，通过mutate()方法获取Builder对象，用于修改其属性
        ServerWebExchange ex = exchange.mutate()
                // 2. 配置修改后的请求对象（ServerHttpRequest）
                // request()方法接收一个函数，用于对请求构建器（ServerHttpRequest.Builder，此处用b代指）进行配置
                // header(String name, String value)：为请求头添加/覆盖指定键值对，这里添加"userInfo"头，值为userInfo变量（存储用户信息）
                .request(b -> b.header("userInfo", userInfo))
                // 3. 完成配置并构建新的ServerWebExchange实例
                // build()方法根据前面的配置，生成一个新的、包含修改后请求头的ServerWebExchange对象
                .build();
        // 6.放行
        return chain.filter(ex);
    }

    private boolean isExclude(String antPath) {
        for (String pathPattern : authProperties.getExcludePaths()) {
            if(antPathMatcher.match(pathPattern, antPath)){
                return true;
            }
        }
        return false;
    }

    @Override
    public int getOrder() {
        return 0;
    }
}

//示例:
/**
 * 全局过滤器：用于拦截未登录状态下的请求访问
 * 实现GlobalFilter接口提供全局过滤能力，实现Ordered接口指定过滤器执行顺序
@Component
public class PrintAnyGlobalFilter implements GlobalFilter, Ordered {

    /**
     * 过滤器核心逻辑处理方法
     *
     * @param exchange 包含请求和响应信息的服务器交换对象
     * @param chain    过滤器链，用于调用后续过滤器
     * @return Mono<Void> 响应完成的信号
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        // 打印未登录提示信息，用于调试或日志记录
        System.out.println("未登录，无法访问");

        // 注释：如果需要放行请求，可使用下面的代码
        // return chain.filter(exchange);

        // 拦截逻辑：获取响应对象
        ServerHttpResponse response = exchange.getResponse();
        // 设置响应状态码为401（未授权）
        response.setRawStatusCode(401);
        // 结束响应，不再继续执行后续过滤器或请求处理
        return response.setComplete();
    }

    /**
     * 指定过滤器的执行顺序
     *
     * @return 顺序值，值越小，过滤器优先级越高，越先执行
    @Override
    public int getOrder() {
        // 返回0表示该过滤器在全局过滤器中具有较高优先级
        return 0;
    }
}
 */